#include <sys/epoll.h>

#include "./Channel.h"
#include "./EventLoop.h"
#include "../utility/Logger.h"

Channel::Channel(EventLoop *loop, int fd)
    : loop_(loop), fd_(fd),
      events_(0), revents_(0), status_(-1), isTied_(false)
{
}

EventLoop *Channel::getEventLoop()
{
    return this->loop_;
}

int Channel::getFd() const
{
    return this->fd_;
}

void Channel::setRevents(int revt)
{
    this->revents_ = revt;
}

int Channel::getEvents() const
{
    return this->events_;
}

void Channel::setStatus(int status)
{
    this->status_ = status;
}

int Channel::getStatus() const
{
    return this->status_;
}

// 注意：kNoneEvent为0只是个标志就用=，kReadEvent等有相应的位EPOLLIN | EPOLLPRI用&
bool Channel::isNoneEvent() const
{
    return this->events_ == kNoneEvent;
}

bool Channel::isReadEvent() const
{
    return this->events_ & kReadEvent;
}

bool Channel::isWriteEvent() const
{
    return this->events_ & kWriteEvent;
}

void Channel::enableReadEvent()
{
    this->events_ |= kReadEvent;
    this->updateChannal();
}

void Channel::disableReadEvent()
{
    this->events_ &= ~kReadEvent;
    this->updateChannal();
}

void Channel::enableWriteEvent()
{
    this->events_ |= kWriteEvent;
    this->updateChannal();
}

void Channel::disableWriteEvent()
{
    this->events_ &= ~kWriteEvent;
    this->updateChannal();
}

void Channel::disableAllEvent()
{
    this->events_ = kNoneEvent;
    this->updateChannal();
}

void Channel::setReadCallback(ReadEventCallback &&cb)
{
    this->readCallback_ = std::move(cb);
}

void Channel::setWriteCallback(EventCallback &&cb)
{
    this->writeCallback_ = std::move(cb);
}

void Channel::setCloseCallback(EventCallback &&cb)
{
    this->closeCallback_ = std::move(cb);
}

void Channel::setErrorCallback(EventCallback &&cb)
{
    this->errorCallback_ = std::move(cb);
}

void Channel::handleEvent(Timestamp &recvTime)
{
    // 绑定过就说明监听过这个channel
    // 弱指针提升强指针，成功说明channel存在才能执行
    // 未绑定的，说明不需要观察，直接执行
    if (this->isTied_)
    {
        std::shared_ptr<void> guard = this->tiePtr_.lock();
        if (guard)
        {
            this->handleEventWithGuard(recvTime);
        }
    }
    else
    {
        this->handleEventWithGuard(recvTime);
    }
}

void Channel::updateChannal()
{
    this->loop_->updateChannel(this);
}

void Channel::handleEventWithGuard(Timestamp &recvTime)
{
    LOG_INFO("channel handleEvent revents:%d\n", this->revents_);

    // EPOLLHUP不需要主动注册
    // 注意：&&判断没有可读数据才关闭
    if ((this->revents_ & EPOLLHUP) && !(this->revents_ & EPOLLIN))
    {
        if (this->closeCallback_)
        {
            this->closeCallback_();
        }
    }

    if (this->revents_ & EPOLLERR)
    {
        if (this->errorCallback_)
        {
            this->errorCallback_();
        }
    }

    if (this->revents_ & (EPOLLIN | EPOLLPRI))
    {
        if (this->readCallback_)
        {
            this->readCallback_(recvTime);
        }
    }

    if (this->revents_ & EPOLLOUT)
    {
        if (this->writeCallback_)
        {
            this->writeCallback_();
        }
    }
}

const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = EPOLLIN | EPOLLPRI;
const int Channel::kWriteEvent = EPOLLOUT;

void Channel::tieChannel(const std::shared_ptr<void> &obj)
{
    this->tiePtr_ = obj;
    this->isTied_ = true;
}

void Channel::removeChannel()
{
    this->loop_->removeChannel(this);
}